package com.zsj.util;

import lombok.extern.slf4j.Slf4j;
import sun.misc.BASE64Decoder;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @Description:
 * @Author:
 * @Date:
 */
@Slf4j
public class RSAUtil {

    private static final String RSA_ALGORITHM = "RSA";
    private static final String DEFAULT_CHARSET = "UTF-8";
    private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";

    public static RSAPrivateKey loadPrivateKey(String privateKeyStr) throws Exception {
        BASE64Decoder base64Decoder = new BASE64Decoder();
        byte[] buffer = base64Decoder.decodeBuffer(privateKeyStr);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
    }

    public static RSAPublicKey loadPublicKey(String publicKeyStr) throws Exception {
        BASE64Decoder base64Decoder = new BASE64Decoder();
        byte[] buffer = base64Decoder.decodeBuffer(publicKeyStr);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        return (RSAPublicKey) keyFactory.generatePublic(keySpec);
    }

    public static String sign(String content, PrivateKey privateKey) {
        try {
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
            signature.initSign(privateKey);
            signature.update(content.getBytes(DEFAULT_CHARSET));
            return Base64.getEncoder().encodeToString(signature.sign());
        } catch (Exception e) {
            log.error("签名异常", e);
            return null;
        }
    }

    public static boolean validate(String content, String sign, PublicKey publicKey) {
        try {
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
            signature.initVerify(publicKey);
            signature.update(content.getBytes(StandardCharsets.UTF_8));
            if (signature.verify(Base64.getDecoder().decode(sign))) {
                return true;
            } else {
                log.error("验签失败，报文:{}，签名:{}", content, sign);
                return false;
            }
        } catch (Exception e) {
            log.error("验签异常", e);
            return false;
        }
    }

    public static void main(String[] args) throws Exception {
        System.out.println(System.currentTimeMillis());
        String publicStr = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjv8cScnT1ymVXFSlboZ8vpTmMqV6SL4XWAdLU96RLOj+Su/eQMy65ST50CeD3Hp8g7RrAMebUS5JSmhaYspLt1+d77UA5BXGNYIuWJFajteVFH2imUqqUER/qPTmGzSnb6V9U4xm3ObcbNeJcOn5A6ATt0FDk3zgfoHk75M18+EC1JZkvBsJGjeS6FBxjAhDIyu119U1JRXY0Va6tH9tN+RiMc4GGWvydZPrrXVN8nDZy3elfVLDZeKXRErnQ+NESTPU83qlxxoIPMU7DJ7etIbfQfq9mx74+GDi9shvQqSCBTFgcx6W5y0G3svjG2ym3Ic0v0XJcMw7JqYifer2twIDAQAB";
        String privateStr = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCO/xxJydPXKZVcVKVuhny+lOYypXpIvhdYB0tT3pEs6P5K795AzLrlJPnQJ4PcenyDtGsAx5tRLklKaFpiyku3X53vtQDkFcY1gi5YkVqO15UUfaKZSqpQRH+o9OYbNKdvpX1TjGbc5txs14lw6fkDoBO3QUOTfOB+geTvkzXz4QLUlmS8GwkaN5LoUHGMCEMjK7XX1TUlFdjRVrq0f2035GIxzgYZa/J1k+utdU3ycNnLd6V9UsNl4pdESudD40RJM9TzeqXHGgg8xTsMnt60ht9B+r2bHvj4YOL2yG9CpIIFMWBzHpbnLQbey+MbbKbchzS/RclwzDsmpiJ96va3AgMBAAECggEAcmOtc3GanwJK0yN7eyDmZWajh1xMqCg4cFjVb3AZ3j08PyIHPvsHfwrHNDaICzWIqasH9gW3P4exZW5475I4Y6Z/pyO6ZLruZhuPi5YrRR07yrp9+fZ6q98/6B6QfK7wSiWuTcmA97FOH1uEPOlOJBJH806oCjHZPBoY03WFsWLaDqZM8c2mKkVI98ctYkEXzHYI3xbqwwt9IpIqH4V+stuZAfHyALmnTrTnknDLBQwyBX6/HeLwZlNzeNG4wgeWwuLtvEhVNBU5ZfJ7CEs31dvVvdgTAN0WzKxwuAzc8uExplenAnSPmP29R70V45r2w7maYojVh48F0GbJ7I7msQKBgQDHMjyGc5JWRw8Y5XUs1bpwU23WOLddUlpfDpoX0ClkBXqFnd0rSfXlwE/Z0xy9nTU15xJz9MXBNC35r0k/tWUQzQZDflqccGrC7/A77xK1jLNy0CZ3PUBefuvIvhWHWSCbw6KwE8X7Yv9R3TkJJfNVQv83u8cCWvZb8itieq7gAwKBgQC3xivpKY2Ibi3IiRnsHc2kfip3cMl5Wv0GbpXcfoQfDUV7v7BC/gwduAxXvh64t3v272riWK1IxxbYLXg/NOCK10czh9O08ALVF1VqpYy1AGRL7Mkvp+L/9KQ8oA5Xadx5zid7xX4KdkFYb3Xlh0S+6yolF98IUjyB5Gxm6NUyPQKBgQCeH8rcEDJCOvZJFR0HEkKFmDTAsRUeB5mli7nW3W997rtsBfzjuDpyv06j42oVOw5aU6vaUJwK2pkEc5j58czgoWAvg8X6GWMmi8FwUj/PznlE0uc2EHFgkfAp0nrUjnPMMmiazZeEDvoOykXUdUPMkvp2C6HWxM57/qlh63GWcQKBgQCIeKXLNIxiME/Xh9i0Oz2nVfn7UMqNUEBuMlkfsOQ0mwpqZ2NhnH8q4q5nykvOKJPqQMlC5U9pqE8SolGVvpKxCEVbwxY4W7P+wqEv3VisYWoZ5/FPboFoSihczQ9ZYsfTvIAdrf93jXHhVoRauyUWElTtzthVuZwtaZAGrAkGkQKBgQC1vgp1gmpHzYTIDGPsFsin0NkWaOCMTwbrZyfpvLazIEG4sUbNNJFZw3XhsRUtT2jhJWcXo6sw9EZUjyBHztm1B27R7rpgxV999PGdG8nziz9sJIOHnPMtJMeGtNW1QSeAvQcf3COndj7qpHQF6QvLbcQI6s8xibtuEmfpPhrtpA==";
        Map<String, Object> requestMap = new HashMap<>(12);
        requestMap.put("AppId", "1234");
        requestMap.put("ChargeNo", "1234");
        requestMap.put("Mobile", "18888888888");
        requestMap.put("CarrierCode", "CM");
        requestMap.put("AdCode", "110000");
        requestMap.put("Timestamp", 1713279189925L);
        requestMap.put("NotifyUrl", "http://sss");
        requestMap.put("ProductDenomination", "1000");
        requestMap.put("BizType", "FEE");
        requestMap.put("SubBizType", "FEE");

        //requestMap.put("AppId", "123");
        //requestMap.put("SupplierCode", "KAILE");
        //requestMap.put("Timestamp", "1713279189925");
        String a = buildContext(requestMap);
        System.out.println(sign(a, loadPrivateKey(privateStr)));

    }

    private static String buildContext(Map<String, Object> requestMap) {
        try {
            Set<String> keySet = requestMap.keySet();
            String[] keyArray = keySet.toArray(new String[0]);
            Arrays.sort(keyArray);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < keyArray.length; i++) {
                if ("Sign".equals(keyArray[i])) {
                    continue;
                }
                // 参数值为空，则不参与签名
                if (String.valueOf(requestMap.get(keyArray[i])).isEmpty()) {
                    continue;
                }
                // 格式为：key1=value1&key2=value2
                sb.append(keyArray[i]).append("=").append(URLEncoder.encode(String.valueOf(requestMap.get(keyArray[i])),
                        "UTF-8"));
                if (i < keyArray.length - 1) {
                    sb.append("&");
                }
            }
            return sb.toString();
        } catch (Exception e) {
            log.error("构造签名报文异常", e);
            return null;
        }
    }

}
